## load libraries
library(tidyverse)
library(ez)
library(lme4)
library(lmerTest)
# set up the theme for plot and rainclound plot
plot_theme = theme(
text = element_text(size = 10),
axis.title = element_text(size = 16),
axis.text = element_text(size = 14), # the size of the texts in plot
# axis.text.x = element_text(angle = 45, vjust = 0.5),
legend.title=element_text(size=16),
legend.text=element_text(size=16),
legend.position = "right",
legend.key.width = unit(1.2, "cm"),
plot.title = element_text(lineheight=.8, face="bold", size = 17),
panel.border = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
axis.line.x = element_line(colour = 'black', size=0.5, linetype='solid'),
axis.line.y = element_line(colour = 'black', size=0.5, linetype='solid', arrow = arrow(length = unit(0.3, "cm"))),
# remove the facet background color
strip.text = element_text(face="bold", size=12, lineheight=5.0),
strip.background = element_rect(fill="white", colour="white", size=1),
strip.placement = "outside"
)
source(file.path("R", "geom_flat_violin.R"))
This R markdown file analyzed the data for the composite face task (complete design) without catch trials. (Experiment number is 104_6)
###### Optional ######
## the filename of the raw data file
fn.raw <- file.path("data","104_106_n-20_2017-05-04-1446.csv")
## input the filename of the output file (.csv)
output.name <- "E1_104_106"
The raw data was loaded from the file named 104_106_n-20_2017-05-04-1446.csv in the data/ folder.
2 Tidying up the data
# read data file
df.raw <- read_csv(fn.raw)
str(df.raw)
# clean and rename the levels of independent variables
df.clean <- {
df.raw %>%
tbl_df() %>% # change into table data frame format
mutate(
Participant = as.factor(Participant),
Congruency = as.factor(Congruency),
Alignment = as.factor(Alignment),
Experiment = as.factor(Experiment),
Congruency = recode(Congruency, "C" = "congruent", "I" = "incongruent"), # rename the levels for Congruency
Alignment = recode(Alignment, "A" = "aligned", "M" = "misaligned"),
Experiment = recode(Experiment, "104_CF_CFS" = "CFS", "106_CF_Mono" = "monocular")
) %>% # rename the levels for Alignment
group_by(Experiment, Participant, Congruency, Alignment, SameDifferent, isCorrect) %>% # divide into groups
mutate(
RT.Z = scale(reactionTime), # calculate the Z value for response times within each group
RT.Within3Z = ifelse(RT.Z <= 3 & RT.Z >= -3, 1, ifelse(RT.Z < -3 | RT.Z > 3, 0, NaN))
) %>% # if the Z values are between -3 and 3, will be marked as 1.
mutate(Stimuli = paste(StudyUpper, StudyLower, TargetUpper, TargetLower, sep = "-")) %>%
ungroup() # ungroup the data
}
df.clean
3 Sensitivity d’
# calculate the d'
individual.d.R <- { # get the hit and correct rejection rates
df.clean %>%
group_by(Experiment, Participant, Congruency, Alignment, SameDifferent) %>% # divide the data into serveral groups
summarize(Accuracy = mean(isCorrect), Count = n()) %>% # get accuracy and count for each condition (hit and correct rejection)
mutate(Accuracy = ifelse(Accuracy == 1, 1 - 0.5/Count, Accuracy)) %>% # set 1 equals to 1-0.5/n
spread(SameDifferent, Accuracy) %>% # spread the Accuracy into two columns based on SameDifferent
mutate(FA = 1 - D,
Z.hit = qnorm(S),
Z.FA = qnorm(FA),
dprime = Z.hit - Z.FA) %>% # get the d prime
select(Experiment, Participant, Congruency, Alignment, dprime, Count)
}
# descriptive statistics of d for plotting
sum.d.R <- {
individual.d.R %>%
group_by(Experiment, Congruency, Alignment) %>%
summarize(Mean = mean(dprime), N = n(), SD = sd(dprime), SE = SD/sqrt(N), SE.hi = Mean + SE, SE.lo = Mean - SE, CI = SE * qt(0.975,N), Median = median(dprime), Lower = Mean - SD, Upper = Mean + SD) %>%
ungroup()
}
# d for SPSS sytle analysis
individual.d.SPSS <- {
individual.d.R %>%
ungroup() %>% # ungroup the data.d.r
mutate(Conditions = paste(Experiment, Congruency, Alignment, sep = ".")) %>% # combine all the levels together
select(Participant, dprime, Conditions, Count) %>% # delete the Independet Variables
spread(Conditions, dprime)
}
# save the d' for R analysis
if (saveCSV) {
write.csv(individual.d.R, output.d.R, row.names = FALSE)
write.csv(individual.d.SPSS, output.d.SPSS, row.names = FALSE)
}
3.1 RainClound plot of sensitivity (d’)
knitr::kable(sum.d.R, digits = 4)
Experiment
Congruency
Alignment
Mean
N
SD
SE
SE.hi
SE.lo
CI
Median
Lower
Upper
CFS
congruent
aligned
2.5001
20
0.6983
0.1561
2.6563
2.3440
0.3257
2.3970
1.8019
3.1984
CFS
congruent
misaligned
2.5646
20
0.5949
0.1330
2.6976
2.4316
0.2775
2.5899
1.9697
3.1596
CFS
incongruent
aligned
2.4831
20
0.7803
0.1745
2.6576
2.3086
0.3640
2.4250
1.7028
3.2634
CFS
incongruent
misaligned
2.5088
20
0.6606
0.1477
2.6565
2.3611
0.3081
2.4161
1.8483
3.1694
monocular
congruent
aligned
2.7825
20
0.5514
0.1233
2.9058
2.6592
0.2572
2.8591
2.2311
3.3339
monocular
congruent
misaligned
2.6769
20
0.7150
0.1599
2.8368
2.5170
0.3335
2.8204
1.9619
3.3920
monocular
incongruent
aligned
2.1700
20
0.8822
0.1973
2.3673
1.9727
0.4115
1.9600
1.2878
3.0522
monocular
incongruent
misaligned
2.4848
20
0.6284
0.1405
2.6253
2.3442
0.2931
2.4381
1.8563
3.1132
d.RainPlot <- {
ggplot(data = individual.d.R, aes(y = dprime, x = Alignment, fill = Congruency)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0), alpha = .7) +
geom_point(aes(y = dprime, color = Congruency), position = position_jitter(width = .15), size = .5, alpha = .8) +
geom_boxplot(aes(y = dprime), width = .2, outlier.shape = NA, alpha = .7) +
geom_point(data = sum.d.R, aes(y = Mean, x = Alignment, color = Congruency), position = position_nudge(x = 0.3), size = 2.5) +
geom_errorbar(data = sum.d.R, aes(y = Mean, ymin = Lower, ymax = Upper), position = position_nudge(x = 0.3), width = 0) +
facet_grid(. ~ Experiment, switch = "both") +
# scale_colour_grey() + # start = .1, end = .6, color for the contour
# scale_fill_grey() + # start = .3, end = .6, color for the fill
# scale_color_brewer(palette = "Set1") +
# scale_fill_brewer(palette = "Set1") +
labs(title = "Sensitivity d' for E104_106", x = "Experiment", y = "Sensitivity", fill = "Congruency", color = "Congruency") + # set the names for main, x and y axises and the legend
# coord_cartesian(ylim = c(0, 6)) + # set the limit for y axis
# scale_y_continuous(expand= c(0, 0)) + # remove the space between columns and x axis
# geom_hline(yintercept = 0, linetype = 5, alpha = 0.5) + # add the line for 0.5 and 1 (y)
theme_bw() + # the backgroud color
plot_theme
}
d.anova <- {
ezANOVA(data = individual.d.R
, dv = dprime
, wid = Participant
, within = c(Experiment, Congruency, Alignment)
, detailed = TRUE
# , type = 3 # for this test, results for type II and III are the same
# , return_aov = TRUE
)
}
knitr::kable(d.anova$ANOVA, digits = 4)
Effect
DFn
DFd
SSn
SSd
F
p
p<.05
ges
(Intercept)
1
19
1017.1601
49.3323
391.7520
0.0000
*
0.9325
Experiment
1
19
0.0083
6.2512
0.0251
0.8757
0.0001
Congruency
1
19
1.9252
4.5127
8.1056
0.0103
*
0.0255
Alignment
1
19
0.2241
3.3359
1.2762
0.2727
0.0030
Experiment:Congruency
1
19
1.3391
2.2886
11.1175
0.0035
*
0.0179
Experiment:Alignment
1
19
0.0354
2.8230
0.2382
0.6311
0.0005
Congruency:Alignment
1
19
0.3641
3.2080
2.1566
0.1583
0.0049
Experiment:Congruency:Alignment
1
19
0.5269
1.8787
5.3283
0.0324
*
0.0071
3.2.2 Sensitivity d’ for CFS: Congruency(2) \(\times\) Alignment(2)
d.ColuPlot = {
ggplot(data = sum.d.R, aes(y = Mean, x = Alignment, color = Congruency, group = Congruency)) + # set the data, varialbes for x and y axises, and the variable for dividing data
geom_point() +
geom_line() + # position = "dodge", alpha = .7
geom_errorbar(mapping = aes(ymin = SE.lo, ymax = SE.hi), linetype = 1, # set the error bar
show.legend = FALSE, width = 0.25, alpha = .5) + # , position = position_dodge(width=0.9)
facet_grid(. ~ Experiment, switch = "both") +
coord_cartesian(ylim = c(0, 4.5)) + # set the limit for y axis
scale_y_continuous(expand= c(0, 0)) + # remove the space between columns and x axis
labs(title = "Sensitivity for E104_106", x = "Experiment", y = "Sensitivity", fill = "Congruency") + # set the names for main, x and y axises
scale_fill_grey() + # set the color for columns
geom_text(label = c("", "", "", "", "***", "", "", ""), color = "red", size = 6, nudge_y = 0.5, nudge_x = 0.5) + # add starts to the significant columns
theme_bw() +
plot_theme
}
d.ColuPlot
4 Correct Response Times
individual.rt.R <- {
df.clean %>%
filter(RT.Within3Z == 1) %>% # only keep the RT within 3 Z
filter(isCorrect == 1) %>% # only keep the correct correct
group_by(Experiment, Participant, Congruency, Alignment) %>% # divide the data into serveral groups
summarize(RT = mean(reactionTime) * 1000 + 300, Count = n()) %>% # get RT and count for each condition
ungroup()
}
# descriptive statistics of RT for plotting
sum.rt.R <- {
individual.rt.R %>%
select(-Count) %>%
group_by(Experiment, Congruency, Alignment) %>%
summarize(Mean = mean(RT), N = n(), SD = sd(RT), SE = SD/sqrt(N), SE.hi = Mean + SE, SE.lo = Mean - SE, CI = SE * qt(0.975,N), Median = median(RT), Lower = Mean - SD, Upper = Mean + SD) %>%
ungroup()
}
# RT for SPSS sytle analysis
individual.rt.SPSS <- {
individual.rt.R %>%
mutate(Conditions = paste(Experiment, Congruency, Alignment, sep = ".")) %>%
select(Participant, Conditions, RT) %>%
spread(Conditions, RT)
}
# save the RT for R analysis
if (saveCSV) {
write.csv(individual.rt.R, output.rt.R, row.names = FALSE)
write.csv(individual.rt.SPSS, output.rt.SPSS, row.names = FALSE)
}
4.1 RainClound plot of correct response times
knitr::kable(sum.rt.R, digits = 4)
Experiment
Congruency
Alignment
Mean
N
SD
SE
SE.hi
SE.lo
CI
Median
Lower
Upper
CFS
congruent
aligned
542.2552
20
124.4380
27.8252
570.0804
514.4300
58.0423
525.4149
417.8172
666.6932
CFS
congruent
misaligned
548.6668
20
124.5759
27.8560
576.5228
520.8107
58.1067
525.4203
424.0908
673.2427
CFS
incongruent
aligned
548.0863
20
137.0902
30.6543
578.7406
517.4320
63.9438
537.7043
410.9960
685.1765
CFS
incongruent
misaligned
537.6101
20
117.2179
26.2107
563.8208
511.3994
54.6746
512.8179
420.3922
654.8280
monocular
congruent
aligned
562.0456
20
115.8470
25.9042
587.9498
536.1414
54.0352
560.2480
446.1986
677.8926
monocular
congruent
misaligned
563.0177
20
122.9075
27.4829
590.5006
535.5347
57.3284
567.5096
440.1102
685.9251
monocular
incongruent
aligned
578.6119
20
118.7580
26.5551
605.1669
552.0568
55.3929
587.7466
459.8539
697.3698
monocular
incongruent
misaligned
565.0116
20
122.5508
27.4032
592.4148
537.6084
57.1620
574.7539
442.4608
687.5624
rt.RainPlot <- {
ggplot(data = individual.rt.R, aes(y = RT, x = Alignment, fill = Congruency)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0), alpha = .7) +
geom_point(aes(y = RT, color = Congruency), position = position_jitter(width = .15), size = .5, alpha = .8) +
geom_boxplot(aes(y = RT), width = .2, outlier.shape = NA, alpha = .7) +
geom_point(data = sum.rt.R, aes(y = Mean, x = Alignment, color = Congruency), position = position_nudge(x = 0.3), size = 2.5) +
geom_errorbar(data = sum.rt.R, aes(y = Mean, ymin = Lower, ymax = Upper), position = position_nudge(x = 0.3), width = 0) +
facet_grid(. ~ Experiment, switch = "both") +
# scale_colour_grey() + # start = .1, end = .6, color for the contour
# scale_fill_grey() + # start = .3, end = .6, color for the fill
# scale_color_brewer(palette = "Set1") +
# scale_fill_brewer(palette = "Set1") +
labs(title = "Correct Response Times for E104_106", x = "Alignment", y = "Response Times (ms)", fill = "Congruency", color = "Congruency") + # set the names for main, x and y axises and the legend
# coord_cartesian(ylim = c(0, 6)) + # set the limit for y axis
# scale_y_continuous(expand = c(0, 0)) + # remove the space between columns and x axis
# geom_hline(yintercept = 0, linetype = 5, alpha = 0.5) + # add the line for 0.5 and 1 (y)
theme_bw() + # the backgroud color
plot_theme
}
rt.anova <- {
ezANOVA(data = individual.rt.R
, dv = RT
, wid = Participant
, within = c(Experiment, Congruency, Alignment)
, detailed = TRUE
# , type = 3 # for this test, results for type II and III are the same
# , return_aov = TRUE
)
}
knitr::kable(rt.anova$ANOVA, digits = 4)
Effect
DFn
DFd
SSn
SSd
F
p
p<.05
ges
(Intercept)
1
19
4.940184e+07
2097279.139
447.5489
0.0000
*
0.9555
Experiment
1
19
2.119146e+04
150925.609
2.6678
0.1189
0.0091
Congruency
1
19
4.445290e+02
3146.660
2.6841
0.1178
0.0002
Alignment
1
19
6.966238e+02
10381.039
1.2750
0.2729
0.0003
Experiment:Congruency
1
19
1.414405e+03
6115.301
4.3945
0.0497
*
0.0006
Experiment:Alignment
1
19
1.833385e+02
17006.359
0.2048
0.6560
0.0001
Congruency:Alignment
1
19
2.474343e+03
9486.172
4.9559
0.0383
*
0.0011
Experiment:Congruency:Alignment
1
19
1.340280e+01
8206.872
0.0310
0.8620
0.0000
4.2.2 Correct RT for CFS: Congruency(2) \(\times\) Alignment(2)
rt.ColuPlot = {
ggplot(data = sum.rt.R, aes(y = Mean, x = Alignment, color = Congruency, group = Congruency)) + # set the data, varialbes for x and y axises, and the variable for dividing data
geom_point() +
geom_line() + # position = "dodge", alpha = .7
geom_errorbar(mapping = aes(ymin = SE.lo, ymax = SE.hi), linetype = 1, # set the error bar
show.legend = FALSE, width = 0.25, alpha = .5) + # , position = position_dodge(width=0.9)
coord_cartesian(ylim = c(0, 1100)) + # set the limit for y axis
scale_y_continuous(expand= c(0, 0)) + # remove the space between columns and x axis
facet_grid(. ~ Experiment, switch = "both") +
labs(title = "Correct Response Times for E104_106", x = "Experiment", y = "Response Times (ms)", fill = "Congruency") + # set the names for main, x and y axises
scale_fill_grey() + # set the color for columns
geom_text(label = c("*", "", "", "", "", "", "", ""), color = "red", size = 6, nudge_y = 30, nudge_x = 0.5) + # add starts to the significant columns
theme_bw() +
plot_theme
}
rt.ColuPlot